package com.hegaoye.filter;

import io.netty.buffer.ByteBufAllocator;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.core.io.buffer.DataBuffer;
import org.springframework.core.io.buffer.DataBufferUtils;
import org.springframework.core.io.buffer.NettyDataBufferFactory;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpRequestDecorator;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.net.URI;
import java.nio.CharBuffer;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.concurrent.atomic.AtomicReference;

@Component
public class TokenFilter implements GlobalFilter, Ordered {
  @Override
  public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

    ServerHttpRequest serverHttpRequest = exchange.getRequest();
    String method = serverHttpRequest.getMethodValue();
    if ("POST".equals(method)) {
      // 从请求里获取Post请求体
      String bodyStr = resolveBodyFromRequest(serverHttpRequest);
      // System.out.println("bodyStr:"+bodyStr);
      // TODO 这里对你获取的参数进行操作，比如 token session 的验证

      // 下面的将请求体再次封装写回到request里，传到下一级，否则，由于请求体已被消费，后续的服务将取不到值
      URI uri = serverHttpRequest.getURI();
      ServerHttpRequest request = serverHttpRequest.mutate().uri(uri).build();
      DataBuffer bodyDataBuffer = stringBuffer(bodyStr);
      Flux<DataBuffer> bodyFlux = Flux.just(bodyDataBuffer);
      request =
          new ServerHttpRequestDecorator(request) {
            @Override
            public Flux<DataBuffer> getBody() {
              return bodyFlux;
            }
          };
      // 封装request，传给下一级
      return chain.filter(exchange.mutate().request(request).build());

    } else if ("GET".equals(method)) {
      Map requestQueryParams = serverHttpRequest.getQueryParams();
      // TODO 得到Get请求的请求参数后，做你想做的事

      return chain.filter(exchange);
    }

    return chain.filter(exchange);
  }

  /** 从Flux<DataBuffer>中获取字符串的方法 */
  private String resolveBodyFromRequest(ServerHttpRequest serverHttpRequest) {
    Flux<DataBuffer> body = serverHttpRequest.getBody();
    AtomicReference<String> bodyRef = new AtomicReference<>();
    body.subscribe(
        buffer -> {
          CharBuffer charBuffer = StandardCharsets.UTF_8.decode(buffer.asByteBuffer());
          DataBufferUtils.release(buffer);
          bodyRef.set(charBuffer.toString());
        });
    return bodyRef.get();
  }

  private DataBuffer stringBuffer(String value) {
    byte[] bytes = value.getBytes(StandardCharsets.UTF_8);

    NettyDataBufferFactory nettyDataBufferFactory =
        new NettyDataBufferFactory(ByteBufAllocator.DEFAULT);
    DataBuffer buffer = nettyDataBufferFactory.allocateBuffer(bytes.length);
    buffer.write(bytes);
    return buffer;
  }

  @Override
  public int getOrder() {
    return 0;
  }
}
